package tasknow.ui;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.wb.swt.SWTResourceManager;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.custom.TableCursor;

import tasknow.commandlogic.Logic;
import tasknow.utils.Constants;
import tasknow.utils.Task;

public class DisplayAndCommandTextComposite extends Composite {

	// @author A0098740W

	private static Table taskTable;
	public static Text commandText;
	private static Text displayBox;

	private static final String ERROR_INVALID_ACTION = "Invalid action detected";

	private static final Character LETTER_Q = 'Q';
	private static final Character LETTER_Y = 'Y';
	private static final Character LETTER_Z = 'Z';
	private static final String COMMAND_SORT_DESCRIPTION = "sort";
	private static final String COMMAND_SORT_START_DATE = "sort s";
	private static final String COMMAND_SORT_END_DATE = "sort e";
	private static final String COMMAND_UNDO = "undo";
	private static final String COMMAND_REDO = "redo";
	private static final String DELETE_TASK = "delete %1$s";
	private static final String MODIFY_DESCRIPTION = "modify %1$s d ";
	private static final String MODIFY_START_DATE_TIME = "modify %1$s s ";
	private static final String MODIFY_END_DATE_TIME = "modify %1$s e ";
	private static final String MARK_TASK = "mark %1$s";

	private static final int HISTORY_LOG_LIMIT = 15;

	private static ArrayList<String> historyCommand = new ArrayList<String>();

	/**
	 * Create the composite.
	 * 
	 * @param parent
	 * @param style
	 */
	public DisplayAndCommandTextComposite(Composite parent, int style) {
		super(parent, style);
		setFont(SWTResourceManager.getFont("Segoe UI", 11, SWT.NORMAL));
		setForeground(SWTResourceManager.getColor(SWT.COLOR_GREEN));
		setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
		setLayout(new GridLayout(1, true));

		Label lblMyTasks = new Label(this, SWT.NONE);
		lblMyTasks.setFont(SWTResourceManager.getFont("Segoe UI", 11, SWT.BOLD
				| SWT.ITALIC));
		lblMyTasks.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
		lblMyTasks.setForeground(SWTResourceManager.getColor(SWT.COLOR_CYAN));
		lblMyTasks.setText("TaskNow");

		taskTable = new Table(this, SWT.BORDER | SWT.FULL_SELECTION);
		taskTable.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.NORMAL));
		taskTable.setForeground(SWTResourceManager.getColor(SWT.COLOR_CYAN));
		taskTable.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
		GridData gd_table = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
		gd_table.heightHint = 211;
		taskTable.setLayoutData(gd_table);
		taskTable.setHeaderVisible(true);
		taskTable.setLinesVisible(false);

		TableColumn tblclmnNumberColumn = new TableColumn(taskTable, SWT.CENTER);
		tblclmnNumberColumn.setResizable(false);
		tblclmnNumberColumn.setWidth(30);
		tblclmnNumberColumn.setText("No");

		TableColumn tblclmnDescriptionColumn = new TableColumn(taskTable,
				SWT.CENTER);
		tblclmnDescriptionColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				try {
					String feedback = Logic.processCommand(COMMAND_SORT_DESCRIPTION);
					showToUser(feedback);
				} catch (IOException e) {
					showToUser(ERROR_INVALID_ACTION);
				}

				refreshDisplay();
			}
		});
		tblclmnDescriptionColumn.setWidth(328);
		tblclmnDescriptionColumn.setText("Description");

		TableColumn tblclmnStartDate = new TableColumn(taskTable, SWT.CENTER);
		tblclmnStartDate.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				try {
					String feedback = Logic.processCommand(COMMAND_SORT_START_DATE);
					showToUser(feedback);
				} catch (IOException e) {
					showToUser(ERROR_INVALID_ACTION);
				}

				refreshDisplay();
			}
		});
		tblclmnStartDate.setWidth(90);
		tblclmnStartDate.setResizable(false);
		tblclmnStartDate.setText("Start Date");

		TableColumn tblclmnStartTime = new TableColumn(taskTable, SWT.CENTER);
		tblclmnStartTime.setWidth(80);
		tblclmnStartTime.setResizable(false);
		tblclmnStartTime.setText("Start Time");

		TableColumn tblclmnEndDate = new TableColumn(taskTable, SWT.CENTER);
		tblclmnEndDate.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				try {
					String feedback = Logic.processCommand(COMMAND_SORT_END_DATE);
					showToUser(feedback);
				} catch (IOException e) {
					showToUser(ERROR_INVALID_ACTION);
				}

				refreshDisplay();
			}
		});
		tblclmnEndDate.setWidth(90);
		tblclmnEndDate.setResizable(false);
		tblclmnEndDate.setText("End Date");

		TableColumn tblclmnEndTime = new TableColumn(taskTable, SWT.CENTER);
		tblclmnEndTime.setWidth(80);
		tblclmnEndTime.setResizable(false);
		tblclmnEndTime.setText("End Time");

		TableColumn tblclmnTaskStatus = new TableColumn(taskTable, SWT.CENTER);
		tblclmnTaskStatus.setWidth(90);
		tblclmnTaskStatus.setResizable(false);
		tblclmnTaskStatus.setText("Task Status");

		final TableCursor tableCursor = new TableCursor(taskTable, SWT.NONE);
		tableCursor.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent arg0) {
				if (arg0.keyCode == SWT.CR || arg0.keyCode == SWT.KEYPAD_CR) {
					TableItem rowData = tableCursor.getRow();
					String rowIndex = rowData.getText();
					int columnIndex = tableCursor.getColumn();

					String toDisplayForModifying = modifyContent(rowIndex, columnIndex);

					if (toDisplayForModifying != null) {
						commandText.setFocus();
						commandText.setText(toDisplayForModifying);
						commandText.setSelection(toDisplayForModifying.length());
					}
				}

				if (arg0.keyCode == SWT.DEL) {
					TableItem rowData = tableCursor.getRow();
					String rowIndex = rowData.getText();

					if (tableCursor.getColumn() == 0) {
						showToUser(Logic.parseCommand(String.format(DELETE_TASK, rowIndex)));
						refreshDisplay();
					}
				}
			}
		});
		tableCursor.setFont(SWTResourceManager.getFont("Segoe UI", 10, SWT.NORMAL));
		tableCursor.setForeground(SWTResourceManager.getColor(SWT.COLOR_BLACK));

		Label lblDisplay = new Label(this, SWT.NONE);
		lblDisplay.setFont(SWTResourceManager.getFont("Segoe UI", 11, SWT.BOLD
				| SWT.ITALIC));
		lblDisplay.setForeground(SWTResourceManager.getColor(SWT.COLOR_CYAN));
		lblDisplay.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
		lblDisplay.setText("Messages");

		displayBox = new Text(this, SWT.BORDER | SWT.READ_ONLY | SWT.V_SCROLL
				| SWT.MULTI);
		displayBox.setFont(SWTResourceManager.getFont("Segoe UI", 10,
				SWT.NORMAL));
		displayBox.setForeground(SWTResourceManager.getColor(SWT.COLOR_CYAN));
		displayBox.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
		GridData gd_text_1 = new GridData(SWT.FILL, SWT.CENTER, true, false, 1,
				1);
		gd_text_1.heightHint = 88;
		displayBox.setLayoutData(gd_text_1);

		Label lblMyCommand = new Label(this, SWT.NONE);
		lblMyCommand.setFont(SWTResourceManager.getFont("Segoe UI", 11,
				SWT.BOLD | SWT.ITALIC));
		lblMyCommand
		.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
		lblMyCommand.setForeground(SWTResourceManager.getColor(SWT.COLOR_CYAN));
		lblMyCommand.setText("Enter Command Here");

		commandText = new Text(this, SWT.BORDER);
		commandText.addMouseTrackListener(new MouseTrackAdapter() {
			@Override
			public void mouseEnter(MouseEvent arg0) {
				commandText.setFocus();
			}
		});
		commandText.setFont(SWTResourceManager.getFont("Segoe UI", 10,
				SWT.NORMAL));
		commandText.setForeground(SWTResourceManager.getColor(SWT.COLOR_CYAN));
		commandText.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
		commandText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
				false, 1, 1));
		commandText.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent arg0) {
				if (arg0.keyCode == SWT.CR || arg0.keyCode == SWT.KEYPAD_CR) {
					String input = commandText.getText();

					try {
						String feedback = Logic.processCommand(input);
						if (feedback.equalsIgnoreCase(Constants.COMMAND_SEARCH)) {
							if (!Logic.getSearchVector().isEmpty()) {
								writeTasksSearchedToTable();
							} else {
								refreshDisplay();
							}
						} else if (feedback.equalsIgnoreCase(Constants.MSG_ARCHIVE_DISPLAYED) || feedback.equalsIgnoreCase(Constants.MSG_EMPTY_ARCHIVE_VECTOR)) {
							writeTasksArchivedToTable();
						} else {
							refreshDisplay();
							showToUser(feedback);
						}
					} catch (IOException e) {
						showToUser(ERROR_INVALID_ACTION);
					}
				}

				if (arg0.keyCode == SWT.F1) {
					Shell shell = new Shell();
					HelpWindowDisplay HelpWindowDisplay = new HelpWindowDisplay(shell, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
				}

				if (arg0.keyCode == SWT.F5) {
					refreshDisplay();
				}
			}
		});

		commandText.addListener(SWT.KeyDown, new Listener() {
			@Override
			public void handleEvent(Event arg0) {
				if (Character.toUpperCase((char)arg0.keyCode) == LETTER_Q &&
						(arg0.stateMask & SWT.CTRL) == SWT.CTRL){
					System.exit(0);
				}

				if (Character.toUpperCase((char)arg0.keyCode) == LETTER_Y &&
						(arg0.stateMask & SWT.CTRL) == SWT.CTRL){
					try {
						String feedback = Logic.processCommand(COMMAND_REDO);
						showToUser(feedback);
					} catch (IOException e) {
						showToUser(ERROR_INVALID_ACTION);
					}

					refreshDisplay();
				}

				if (Character.toUpperCase((char)arg0.keyCode) == LETTER_Z &&
						(arg0.stateMask & SWT.CTRL) == SWT.CTRL){
					try {
						String feedback = Logic.processCommand(COMMAND_UNDO);
						showToUser(feedback);
					} catch (IOException e) {
						showToUser(ERROR_INVALID_ACTION);
					}

					refreshDisplay();
				}
			}
		});

	}

	private static String modifyContent(String rowIndex, int columnIndex) {
		switch(columnIndex) {
			case 0:
				return String.format(DELETE_TASK, rowIndex);
	
			case 1:
				return String.format(MODIFY_DESCRIPTION, rowIndex);
	
			case 2:
				return String.format(MODIFY_START_DATE_TIME, rowIndex);
	
			case 3:
				return String.format(MODIFY_START_DATE_TIME, rowIndex);
	
			case 4:
				return String.format(MODIFY_END_DATE_TIME, rowIndex);
	
			case 5:
				return String.format(MODIFY_END_DATE_TIME, rowIndex);
	
			case 6:
				return String.format(MARK_TASK, rowIndex);
	
			default:
				return null;
		}
	}

	private static void refreshDisplay() {
		writeToAllTables();
		commandText.setText(Constants.EMPTY_STRING);
		commandText.setFocus();
	}

	public static void writeToAllTables() {
		writeToMainTable();
		ActiveTasksComposite.writeToTodaysTable();
		ActiveTasksComposite.writeToWeeksTable();
	}

	public static void writeToMainTable() {
		taskTable.removeAll();

		for (int i = 0; i < Logic.getCurrentTaskVector().size(); i++) {
			TableItem tableItem = new TableItem(taskTable, SWT.NONE);
			writeToColumn(i, Logic.getCurrentTaskVector().get(i), tableItem);
		}
	}

	public static void writeTasksSearchedToTable() {
		taskTable.removeAll();

		for (int i = 0; i < Logic.getSearchVector().size(); i++) {
			TableItem tableItem = new TableItem(taskTable, SWT.NONE);
			writeToColumn(i, Logic.getSearchVector().get(i), tableItem);
		}
	}

	protected void writeTasksArchivedToTable() {
		taskTable.removeAll();

		for (int i = 0; i < Logic.getArchivedVector().size(); i++) {
			TableItem tableItem = new TableItem(taskTable, SWT.NONE);
			writeToColumn(i, Logic.getArchivedVector().get(i), tableItem);
		}
	}

	private static void writeToColumn(int rowIndex, Task task, TableItem tableItem) {
		tableItem.setText(new String[] {
				Integer.toString(rowIndex + Constants.ADJUST_INDEX_BY_1),
				task.getDescription(), task.getStartDateString(),
				task.getStartTimeString(), task.getEndDateString(),
				task.getEndTimeString(), task.getTaskStatusString() });
	}

	public static void showToUser(String messageToUser) {
		if (!messageToUser.equalsIgnoreCase(Constants.EMPTY_STRING)) {
			updateHistoryCommands(messageToUser);
			String toDisplay = setDisplay();
			displayBox.setText(toDisplay);
			displayBox.setSelection(toDisplay.length() + 1);
		}
	}

	private static void updateHistoryCommands(String messageToUser) {
		if (historyCommand.size() >= HISTORY_LOG_LIMIT) {
			historyCommand.remove(Constants.ZEROTH);
		}

		historyCommand.add(messageToUser);
	}

	private static String setDisplay() {
		String historyDisplay = Constants.EMPTY_STRING;

		for (int i = 0; i < historyCommand.size(); i++) {
			if (i < historyCommand.size() - 1) {
				historyDisplay += historyCommand.get(i) + Constants.NEW_LINE;
			} else {
				historyDisplay += historyCommand.get(i);
			}
		}

		return historyDisplay;
	}

	public static void loadTasksToTaskNow() {
		Logic.initiateStorage();
		showToUser(Constants.MSG_WELCOME);
	}

	public static void initialiseDisplay() {
		try {
			Logic.processCommand(COMMAND_SORT_END_DATE);
		} catch (IOException e) {
			showToUser(Constants.MSG_SORT_EMPTY_FILE);
		}

		String listOfTodaysTasks = Logic.getTodayTasks();
		showToUser(listOfTodaysTasks);
		Logic.getTodayNotification();

		String listOfWeeksTasks = Logic.getNextWeekTasks();
		showToUser(listOfWeeksTasks);
	}

	public static void readyTaskNow() {
		writeToAllTables();
		commandText.setFocus();
	}

	public static Vector<Task> pullTodaysTasks() {
		return Logic.getTodayTasksVector();
	}

	public static Vector<Task> pullNextWeeksTasks() {
		return Logic.getNextWeekTasksVector();
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}

}
